<?php

// mk_status_img.php
// Michael Baker
// 2010.06.24
//
// output a status image based on data from a serialized workflow
// (obtained from the session header) and a query timeframe in seconds

session_start();
define( "IN_MDM", true );
require_once( "includes/all.php" );

/* Declare some constants */
define( "FAULT_LOSS", 0 );
define( "FAULT_DELAY", 1 );
define( "FAULT_PDV", 2 );
define( "IMG_WIDTH", 1000 );
define( "TRIANGLE", 3 );

// Unserialize the workflow, retrieve names and colorcodes, etc.
$workflow    = unserialize( $_SESSION[ "wf" ] );
$fault_names = $workflow->get_fault_names();
$fault_count = count( $fault_names );
$seg_names   = $workflow->get_seg_names();
$seg_count   = count( $seg_names );
$wf_colors   = $workflow->get_colorcodes();

/* General image measurements */
$pad     = 20;     // padding around the image
$curX    = $pad;   // start at the left of the image
$curY    = $pad;   // start at the top of the image
$spacerV = 10;     // vertical spacer
$spacerH = 10;     // horizontal spacer
$faultSpacer = 20; // spacer between faults

/* General font declarations */
$font    = 2;      // fault data font
$fontB   = 3;      // bold font
$font2   = 5;      // title font

/* Properties of "main" lines */
$lineW   = IMG_WIDTH - (2 * $pad);
$lineH   = 5;
$lineVS  = 5;

/* Properties of "main" arrowheads */
$triangleW = 25;
$triangleH = 15;

/* Properties of smaller lines */
$subLineVS    = 25;
$subLineW     = (IMG_WIDTH - 2 * $pad -
                ($seg_count - 1) * $spacerH) /
                $seg_count;
$subLineH     = 2;
$subTriangleW = 15;
$subTriangleH = 10;

/* Determine image height based on what we "expect" we will need */
$height = $pad + ( imagefontheight($font2) + $spacerV ) +                   // 1. main title and v. spacer
          ( imagefontheight($font2) + $spacerV ) +                          // 2. site titles and v. spacer
          ( $lineVS + $triangleH ) +                                        // 3. top main line and line spacer
          ( $triangleH + $spacerV ) +                                       // 4. bottom main line and v. spacer
          ( imagefontheight($font2) + $spacerV )  +                         // 5. segment titles and v. spacer
          $fault_count * ( 2 * $subTriangleH + imagefontheight($fontB) ) +  // 6. one fault from tip of top arrow to tip of bottom arrow
          ($fault_count - 1) * $faultSpacer +                               // 7. spacers between faults (faultCount-1 of them)
          $pad;                                                             // X. extra padding at bottom of image
define( "IMG_HEIGHT", $height );

/* Create image, initialize the colours that are in the database */
$im        = imagecreatetruecolor( IMG_WIDTH, IMG_HEIGHT );
$codes     = $dbase->list_colorcodes();
$colors    = array();

foreach ( array_keys( $codes ) as $cc )
  $colors[ $cc ] = imagecolorallocate( $im, $codes[$cc][0], $codes[$cc][1], $codes[$cc][2] );
  
/* Initialize other colours which we will need */
$white = imagecolorallocate( $im, 255, 255, 255 );
$blue  = imagecolorallocate( $im, 0, 255, 255 );

/* 1. Create: Centered title at top of image + vertical spacer */
$string    = "perfSONAR E2E Monitor";
$xPos      = ( imagesx( $im ) - imagefontwidth( $font2 ) * strlen( $string ) ) / 2;
imagestring( $im, $font2, $xPos, $curY, $string, $white );
$curY += imagefontheight( $font2 ) + $spacerV;

/* 2. Create: Site titles at left and right side + vertical spacer */
$endpoints = $workflow->get_endpoints();
$start_node = $endpoints[ 0 ];
$end_node   = $endpoints[ 1 ];
$start_title = $start_node->get_title();
$end_title   = $end_node->get_title();
$string = $start_title;
imagestring( $im, $font2, $curX, $curY, $string, $blue );
$string = $end_title;
$xPos   = IMG_WIDTH - ( $pad + strlen( $string ) * imagefontwidth( $font2 ) );
imagestring( $im, $font2, $xPos, $curY, $string, $blue );
$curY += imagefontheight( $font2 ) + $spacerV;

/* 3. Create: Top main line + line spacer */ 
$cc_left  = $wf_colors[ 0 ];          // leftward arrow color ID
$c_left   = $colors[ $cc_left ];      // Gd color for leftward arrow
$triangleVertices = array( $curX + $triangleW, $curY, $curX + $triangleW, $curY + $triangleH, $curX, $curY + $triangleH );
imagefilledpolygon( $im, $triangleVertices, 3, $c_left );
imagefilledrectangle( $im, $curX + $triangleW, $curY + $triangleH, $curX + $lineW, $curY + $triangleH - $lineH, $c_left );
$curY += $lineVS + $triangleH;

/* 4. Create: Bottom main line + vertical spacer */
$cc_right = $wf_colors[ 1 ];          // rightward arrow color ID
$c_right  = $colors[ $cc_right ];     // Gd color for rightward arrow
$triangleVertices = array( IMG_WIDTH - ( $curX + $triangleW ), $curY + $triangleH, IMG_WIDTH - $curX, $curY, IMG_WIDTH - ( $curX + $triangleW ), $curY );
imagefilledpolygon( $im, $triangleVertices, 3, $c_right );
imagefilledrectangle( $im, $curX, $curY, $curX + $lineW - $triangleW, $curY + $lineH, $c_right );
$curY += $spacerV + $triangleH;

// Loop to create sublines
$counter = 0;
$baseY   = $curY;
while ( $counter < $seg_count ) {

  /* 5. Create: Segment title */
  $i = $counter+1;
  $string = "$i - " . ($seg_names[ $counter ] ? $seg_names[ $counter ] : "(unknown)");
  $xPos   = $pad + $counter * $spacerH + $counter * $subLineW + 0.5*$subLineW - 0.5*strlen($string)*imagefontwidth($font2);
  $yPos   = $baseY;
  imagestring( $im, $font2, $xPos, $yPos, $string, $blue );
  $yPos   += imagefontheight( $font2 );
  
  /* Resolve segment fault data */
  $seg_num_array = $workflow->get_fault_numerics( $counter );
  $seg_extra_array = $workflow->get_fault_extras( $counter );
  
  /* Resolve segment colorcodes */
  $cc_array = $workflow->get_seg_colorcodes( $counter );
  
  // Loop through this segment's faults
  $fault_ctr = 0;
  while ( $fault_ctr < $fault_count ) {
    
    /* Get fault data for this specific fault */
    $num_array = $seg_num_array[ $fault_ctr ];
    $extra_array = $seg_extra_array[ $fault_ctr ];
    $num_left = floatval( $num_array[ 0 ] );
    $num_right = floatval( $num_array[ 1 ] );
    
    /* Format fault data */
    if ( $fault_ctr == FAULT_LOSS ) {
      $num_left_f = number_format( $num_left, 0 );
      $num_right_f = number_format( $num_right, 0 );
      $sum_left_f = number_format( $extra_array[ "OVERALL" ][ 0 ], 0 );
      $sum_right_f = number_format( $extra_array[ "OVERALL" ][ 1 ], 0 );
      
      $label_l = ($num_left_f) ? "<< $num_left_f" : "";
      $label_r = ($num_right_f) ? "$num_right_f >>" : "";
      $label2_l = ($sum_left_f) ? "Total: $sum_left_f" : "";
      $label2_r = ($sum_right_f) ? "Total: $sum_right_f" : "";
    }
    elseif ( $fault_ctr == FAULT_DELAY ) {
      $num_left_f = number_format( $num_left * 1000, 1 ) . "ms";
      $num_right_f = number_format( $num_right * 1000, 1 ) . "ms";
      $abs_left_f = number_format( $extra_array[ "OVERALL" ][ 0 ] * 1000, 1 ) . "ms";
      $abs_right_f = number_format( $extra_array[ "OVERALL" ][ 1 ] * 1000, 1 ) . "ms";
      
      $label_l = ($num_left_f) ? "<< $num_left_f" : "";
      $label_r = ($num_right_f) ? "$num_right_f >>" : "";
      $label2_l = ($abs_left_f) ? "Abs: $abs_left_f" : "";
      $label2_r = ($abs_right_f) ? "Abs: $abs_right_f" : "";
    }
    else {
      error_log( "mk_status_img failed: Unexpected fault ID: $fault_ctr" );
      die;
    }
    
    /* Retrieve colorcodes and Gd colors for this fault */
    $cc = $cc_array[ $fault_ctr ];
    $cc_left = $cc[ 0 ];
    $cc_right = $cc[ 1 ];
    $c_left = $colors[ $cc_left ];
    $c_right = $colors[ $cc_right ];
    
    /* 6-7. Create: Arrow indicators for this fault/spacers between faults */
    $xPos  = $pad + $counter * $spacerH + $counter * $subLineW;    
    $yPos += $subTriangleH;
    
    // Label above leftward arrow
    imagestring( $im, $font, $xPos + $subTriangleW + 2, $yPos - $subLineH - 2, $label2_l, $white );
    
    // Leftward arrow: draw arrowhead and then the line itself
    $triangleVertices = array( $xPos + $subTriangleW, $yPos, $xPos + $subTriangleW, $yPos + $subTriangleH, $xPos, $yPos + $subTriangleH );
    imagefilledpolygon( $im, $triangleVertices, TRIANGLE, $c_left );
    imagefilledrectangle( $im, $xPos + $subTriangleW, $yPos + $subTriangleH, $xPos + $subLineW, $yPos + $subTriangleH - $subLineH, $c_left );  
    $yPos += $subTriangleH;
    
    // Left and right numerics (<< and >>)
    imagestring( $im, $font, $xPos, $yPos, $label_l, $white );
    imagestring( $im, $font, $xPos + $subLineW - imagefontwidth($font) * strlen($label_r), $yPos, $label_r, $white );
    
    // Fault title between arrows
    $string = $fault_names[ $fault_ctr ];
    imagestring( $im, $fontB, $xPos + 0.5 * $subLineW - 0.5 * strlen( $string ) * imagefontwidth( $font ), $yPos, $string, $white );
    $yPos += imagefontheight($font);
    $xPos += $subLineW;
    
    // Rightward arrow: draw arrowhead and then the line itself
    $triangleVertices = array( $xPos, $yPos, $xPos - $subTriangleW, $yPos, $xPos - $subTriangleW, $yPos + $subTriangleH );
    imagefilledpolygon( $im, $triangleVertices, TRIANGLE, $c_right );
    imagefilledrectangle( $im, $xPos - $subTriangleW, $yPos, $xPos - $subLineW, $yPos + $subLineH, $c_right );
    
    // Label below rightward arrow
    imagestring( $im, $font, $xPos - $subTriangleW - strlen($label2_r)*imagefontwidth($font), $yPos + $subLineH, $label2_r, $white );
    
    if ( $fault_ctr !== ( $fault_count - 1 ) ) {
      // If we are not on the last fault, create a vertical spacer
      $yPos += $faultSpacer;
    }
     
    $fault_ctr += 1;
  }
  
  $counter += 1;

}

// Output full quality JPEG
header( "Content-type: image/jpeg" );
imagejpeg( $im, NULL, 100 );
imagedestroy( $im );

?>